package com.nettyServer.server;

import com.nettyServer.handler.ServerHandler;
import com.nettyServer.protoHandler.MyDecoder;
import com.nettyServer.protoHandler.PackageSpliter;
import com.nettyServer.protoHandler.ProtobufEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @program: SpringBootDemos
 * @description:
 * @author: Kangsen
 * @create: 2022-08-01 14:07
 * <p>
 * 单例模式的
 **/
@Slf4j
public class StartNetty {

    private StartNetty(){}

    private static class SingletonStartNetty {
        static final StartNetty instance = new StartNetty();
    }

    public static StartNetty getInstance() {
        return SingletonStartNetty.instance;
    }

    public void start(int port) {
        InetSocketAddress socketAddress = new InetSocketAddress("0.0.0.0",port);
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap()
                .group(bossGroup, workerGroup)
                //使用NioServerSocketChannel 作为服务器的通道实现
                .channel(NioServerSocketChannel.class)
                //设置线程队列 得到连接个数
                .option(ChannelOption.SO_BACKLOG, 128)
                .localAddress(socketAddress)
                //设置保持活动连接状态
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                //通过Nodelay禁用nagle 使消息立即发出去，不用等到一定的数据量才发
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                //日志处理器
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                                  //给pipeline设置 处理器
                                  @Override
                                  protected void initChannel(SocketChannel socketChannel) throws Exception {
                                      ChannelPipeline pipeline = socketChannel.pipeline();
                                      pipeline.addLast(new PackageSpliter());
                                      pipeline.addLast(new MyDecoder());
                                      //对String 对象自动编解码 属于出站处理器
                                      pipeline.addLast(new StringEncoder());
                                      //把网络字节流自动转为String 属于入站处理器
                                      pipeline.addLast(new StringDecoder());

                                      pipeline.addLast(new ProtobufEncoder());
                                      //pipeline.addLast(new ProtobufDecoder());
                                      //LengthFieldBasedFrameDecoder拆包器  最前面用自定义的来拆包
                                      //pipeline.addLast(new LengthFieldBasedFrameDecoder(24 * 1024, 0, 2));
                                      //自定义的handler
                                      pipeline.addLast(new ServerHandler());
                                  }
                              }
                );

        try {
            ChannelFuture channelFuture = serverBootstrap.bind(socketAddress).sync();
            log.info("netty server is started on {}",socketAddress);
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
